package cn.smalltool.core.utils;

import cn.smalltool.core.date.DateUtil;
import cn.smalltool.core.lang.Assert;
import cn.smalltool.core.lang.PatternPool;
import cn.smalltool.core.lang.Validator;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 身份证工具
 */
public class IdcardUtil {

    private static final int CHINA_ID_MIN_LENGTH = 15;
    private static final int CHINA_ID_MAX_LENGTH = 18;
    private static final int[] power = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
    private static final Map<String, String> CITY_CODES = new HashMap<>();

    public static boolean isValidCard(String idCard) {
        idCard = idCard.trim();
        int length = idCard.length();
        switch(length) {
            case 15:
                return isValidCard15(idCard);
            case 18:
                return isValidCard18(idCard);
            default:
                return false;
        }
    }

    public static boolean isValidCard18(String idCard) {
        if (18 != idCard.length()) {
            return false;
        } else {
            String proCode = idCard.substring(0, 2);
            if (null == CITY_CODES.get(proCode)) {
                return false;
            } else if (!Validator.isBirthday(idCard.substring(6, 14))) {
                return false;
            } else {
                String code17 = idCard.substring(0, 17);
                char code18 = Character.toLowerCase(idCard.charAt(17));
                if (ReUtil.isMatch(PatternPool.NUMBERS, code17)) {
                    char val = getCheckCode18(code17);
                    return val == code18;
                } else {
                    return false;
                }
            }
        }
    }

    private static char getCheckCode18(String code17) {
        int sum = getPowerSum(code17.toCharArray());
        return getCheckCode18(sum);
    }

    private static char getCheckCode18(int iSum) {
        switch(iSum % 11) {
            case 0:
                return '1';
            case 1:
                return '0';
            case 2:
                return 'x';
            case 3:
                return '9';
            case 4:
                return '8';
            case 5:
                return '7';
            case 6:
                return '6';
            case 7:
                return '5';
            case 8:
                return '4';
            case 9:
                return '3';
            case 10:
                return '2';
            default:
                return ' ';
        }
    }

    private static int getPowerSum(char[] iArr) {
        int iSum = 0;
        if (power.length == iArr.length) {
            for(int i = 0; i < iArr.length; ++i) {
                iSum += Integer.parseInt(String.valueOf(iArr[i])) * power[i];
            }
        }

        return iSum;
    }

    public static boolean isValidCard15(String idCard) {
        if (15 != idCard.length()) {
            return false;
        } else if (ReUtil.isMatch(PatternPool.NUMBERS, idCard)) {
            String proCode = idCard.substring(0, 2);
            if (null == CITY_CODES.get(proCode)) {
                return false;
            } else {
                return Validator.isBirthday("19" + idCard.substring(6, 12));
            }
        } else {
            return false;
        }
    }

    /**
     * 根据身份证获取性别
     * @param idCard 身份证号码
     * @return 1-男性 0-女性
     */
    public static int getGenderByIdCard(String idCard) {
        Assert.notBlank(idCard);
        int len = idCard.length();
        if (len < 15) {
            throw new IllegalArgumentException("ID Card length must be 15 or 18");
        } else {
            if (len == 15) {
                idCard = convert15To18(idCard);
            }

            char sCardChar = Objects.requireNonNull(idCard).charAt(16);
            return sCardChar % 2 != 0 ? 1 : 0;
        }
    }

    public static String convert15To18(String idCard) {
        if (idCard.length() != 15) {
            return null;
        } else if (ReUtil.isMatch(PatternPool.NUMBERS, idCard)) {
            String birthday = idCard.substring(6, 12);
            Date birthDate = DateUtil.parse(birthday, "yyMMdd");
            int sYear = DateUtil.year(birthDate);
            if (sYear > 2000) {
                sYear -= 100;
            }

            StringBuilder idCard18 = StrUtil.builder().append(idCard, 0, 6).append(sYear).append(idCard.substring(8));
            char sVal = getCheckCode18(idCard18.toString());
            idCard18.append(sVal);
            return idCard18.toString();
        } else {
            return null;
        }
    }

    static {
        CITY_CODES.put("11", "北京");
        CITY_CODES.put("12", "天津");
        CITY_CODES.put("13", "河北");
        CITY_CODES.put("14", "山西");
        CITY_CODES.put("15", "内蒙古");
        CITY_CODES.put("21", "辽宁");
        CITY_CODES.put("22", "吉林");
        CITY_CODES.put("23", "黑龙江");
        CITY_CODES.put("31", "上海");
        CITY_CODES.put("32", "江苏");
        CITY_CODES.put("33", "浙江");
        CITY_CODES.put("34", "安徽");
        CITY_CODES.put("35", "福建");
        CITY_CODES.put("36", "江西");
        CITY_CODES.put("37", "山东");
        CITY_CODES.put("41", "河南");
        CITY_CODES.put("42", "湖北");
        CITY_CODES.put("43", "湖南");
        CITY_CODES.put("44", "广东");
        CITY_CODES.put("45", "广西");
        CITY_CODES.put("46", "海南");
        CITY_CODES.put("50", "重庆");
        CITY_CODES.put("51", "四川");
        CITY_CODES.put("52", "贵州");
        CITY_CODES.put("53", "云南");
        CITY_CODES.put("54", "西藏");
        CITY_CODES.put("61", "陕西");
        CITY_CODES.put("62", "甘肃");
        CITY_CODES.put("63", "青海");
        CITY_CODES.put("64", "宁夏");
        CITY_CODES.put("65", "新疆");
        CITY_CODES.put("71", "台湾");
        CITY_CODES.put("81", "香港");
        CITY_CODES.put("82", "澳门");
        CITY_CODES.put("91", "国外");
    }
}
